#pragma once
#include <iostream>
#include <cstdlib>
#include <wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
#include <pthread.h>
#include <signal.h>
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"
const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 5;
extern Log lg;
enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError
};
class TcpServer;
class ThreadData
{
public:
    ThreadData(int fd, const std::string &ip, const uint16_t &p, TcpServer *t)
        : sockfd(fd), clientip(ip), clientport(p), tsvr(t)
    {
    }

public:
    int sockfd;
    std::string clientip;
    uint16_t clientport;
    TcpServer *tsvr;
};
class TcpServer
{
public:
    TcpServer(const uint16_t &port, const std::string &ip = defaultip) : listensockfd_(defaultfd),
                                                                         port_(port), ip_(ip)
    {
    }
    void initServer()
    {
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
        if (listensockfd_ < 0)
        {
            lg(Fatal, "create listensockfd_,error: %d,errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create listensockfd_ success,sockfd: %d", listensockfd_);
        int opt = 1;
        setsockopt(listensockfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); // 设置套接字属性

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;                // 确定协议家族
        local.sin_port = htons(port_);             // 绑定端口
        inet_aton(ip_.c_str(), &(local.sin_addr)); // 将string类型的ip转换为4字节的点分十进制类型
        // 输入ip地址的第二种方法 local.sin_addr.s_addr=INADDR_ANY
        if (bind(listensockfd_, (struct sockaddr *)&local, sizeof(local)) < 0) // 绑定套接字，将端口、协议家族等信息写入内核
        {
            lg(Fatal, "bind error,error: %d.errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind listensockfd_ success,sockfd: %d", listensockfd_);

        // TCP是面向连接的，服务器一直处于一种被动等待连接的状态
        if (listen(listensockfd_, backlog) < 0)
        {
            lg(Fatal, "listen error,errno: %d,errstring :%s", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info, "listen socket success,sockfd: %d", listensockfd_);
    }
    static void *Routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args); // 强制转换
        td->tsvr->Service(td->sockfd, td->clientip, td->clientport);
        delete td;
        return nullptr;
    }
    void start()
    {

        // signal(SIGPIPE, SIG_IGN); // 是忽略SIGPIPE信号
        // Daemon(); // 守护进程
        ThreadPool<Task>::GetInstance()->Start();
        lg(Info, "tcpServer is running...");
        for (;;)
        {
            struct sockaddr_in client; // 存储远端的客户端信息的结构体
            socklen_t len = sizeof(client);
            // 接收客户端传来的请求 ,返回的套接字用于和客户端进行通信
            int sockfd = accept(listensockfd_, (struct sockaddr *)&client, &len); // 注意sockfd和sockfd_的区别和作用
            if (sockfd < 0)
            {
                lg(Warning, "listen error,errno: %d,errstring :%s", errno, strerror(errno));
                continue;
            }
            // accept会知道是哪个客户端连接的我，并把客户端的信息存储到client结构体中
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));
            lg(Info, "get a new link....,sockfd: %d,client ip:%s,client port: %d\n", sockfd, clientip, clientport);
            // 正式通信，单进程版本v1,只能服务一个客户端，
            // 其他客户端在这个服务端服务其他客户端时只能等待
            // Service(sockfd, clientip, clientport);
            // close(sockfd);
            // 多进程版
            /* pid_t id = fork();
             if (id == 0)
             {                         // 子进程通信
                 close(listensockfd_); // 子进程能看到但是不需要的文件描述符，可以把子进程的这个文件描述符关闭
                 if (fork() > 0)
                     exit(0);
                 Service(sockfd, clientip, clientport); // 以下代码孙子进程做，最后被领养
                 close(sockfd);
                 exit(0);
             }
             // 父进程继续等待新连接的到来
             close(sockfd); // 父进程可以不关心本进程的sockfd了，由子进程关心这个sockfd就得了
             pid_t rid = waitpid(id, nullptr, 0);
             (void)rid;*/
            // 多线程版本
            /*ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, (void *)td);*/
            // 线程池，任务从网络来
            Task t(sockfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }
    void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)
    {
        /*char buffer[4096];
        while (true)
        {
            ssize_t n = read(sockfd, buffer, sizeof(buffer));
            if (n > 0)
            {
                buffer[n] = 0;
                std::cout << "client say#" << buffer << std::endl;
                std::string echo_string = "tcpserver echo# ";
                echo_string += buffer;
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0)
            {
                lg(Info, "%s:%d quit,server close sockfd: %d",
                   clientip.c_str(), clientport, sockfd);
                break;
            }
            else
            {
                lg(Warning, "read error,sockfd: %d,client ip:%s,client port: %d\n",
                   sockfd, clientip.c_str(), clientport);
                // std::cout << "read读取失败" << std::endl;
                break;
            }
        }*/
    }

    ~TcpServer()
    {
    }

private:
    int listensockfd_;
    uint16_t port_;
    std::string ip_;
};